package com.bsi.rd.framework.zuul.filter;


import com.alibaba.fastjson.JSONObject;
import com.bsi.rd.framework.zuul.pojo.ResultJson;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


/*
 * Author: liusongs
 * Date: 2019/12/18 15:13
 * Content: 处理网关出现的异常,例如forwording error,timeout error 等等再次处理异常
 */
public class ErrorFilter extends ZuulFilter {
    private final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);

    /**
     * 过滤器类型选择：
     * pre 为路由前
     * route 为路由过程中
     * post 为路由过程后
     * error 为出现错误的时候
     * 同时也支持static ，返回静态的响应，详情见StaticResponseFilter的实现
     * 以上类型在会创建或添加或运行在FilterProcessor.runFilters(type)
     */
    @Override
    public String filterType() {
        return "error";
    }

    /**
     * 用来过滤器排序执行的
     *
     * @return 排序的序号
     */
    @Override
    public int filterOrder() {
        return -1; //设置-1则是因为要在默认的sendErrorFilter前执行
    }

    /**
     * 是否通过这个过滤器，默认为true，改成false则不启用
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的逻辑
     */
    @Override
    public Object run() throws ZuulException {
        try {
            logger.error("==================网关出现异常，开始处理========================");
            RequestContext requestContext = RequestContext.getCurrentContext();
            Object e = requestContext.get("throwable");
            if (e != null && e instanceof ZuulException) {
                ZuulException zuulException = (ZuulException) e;
                logger.error("异常信息为:{}", zuulException.getCause().getMessage());
                String serviceId = (String) (requestContext.get("serviceId"));
                logger.error("异常请求路径为:{},请求serviceId为:{}", requestContext.get("requestURI"), serviceId);
                // 删除该异常信息,不然在下一个过滤器中还会被执行处理
                requestContext.remove("throwable");
                // 响应给客户端信息
                writeOut(requestContext, serviceId);
                logger.error("==================网关出现异常，结束处理========================");
            }
        } catch (Exception ex) {
            logger.error("Exception filtering in ErrorFilter", ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }
        return null;
    }

    private void writeOut(RequestContext requestContext, String serviceId) throws IOException {
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter pw = null;
        pw = response.getWriter();
        pw.write(JSONObject.toJSONString(ResultJson.createError(HttpServletResponse.SC_BAD_GATEWAY, serviceId + "服务未启动或连接超时...请联系管理员")));
        pw.close();
    }
}
